package com.ltu.payment.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author 少凡
 * @date 2020/2/8 15:43
 */
public class RsaUtil {

    /**
     * 指定key的大小
     */
    private static final String CHARSET = "UTF-8";
    private static final String KEY_ALGORITHM = "RSA";
    private static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";

    /**
     * Rsa私钥加密
     *
     * @param source     需要加密源字符串
     * @param privateKey 私钥
     * @return
     */
    public static String encrypt(String source, String privateKey) {
        try {
            Key key = getPrivateKey(privateKey);
            /** 得到Cipher对象来实现对源数据的RSA加密 */
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(source.getBytes());
            return Base64.encodeBase64String(result);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("RSA加密出错！");
        }
    }

    /**
     * Rsa公钥解密
     * @param cryptograph 密文
     * @param publicKey   公钥
     * @return
     */
    public static String decrypt(String cryptograph, String publicKey) {
        try {
            Key key = getPublicKey(publicKey);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] result = cipher.doFinal(Base64.decodeBase64(cryptograph));
            return new String(result);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("RSA解密出错！");
        }
    }

    /**
     * Rsa签名
     *
     * @param content    签名内容
     * @param privateKey 私钥
     * @return
     */
    public static String sign(String content, String privateKey) {

        try {
            PrivateKey key = getPrivateKey(privateKey);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initSign(key);
            signature.update(content.getBytes(CHARSET));
            byte[] signed = signature.sign();
            return new String(Base64.encodeBase64(signed));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("RSA签名出错！");
        }
    }


    /**
     * RSA验签
     * @param content 签名内容
     * @param sign 签名
     * @param publicKey 公钥
     * @return
     */
    public static boolean verifySign(String content, String sign, String publicKey) {

        try {
            PublicKey key = getPublicKey(publicKey);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(key);
            signature.update(content.getBytes(StandardCharsets.UTF_8));
            return signature.verify(Base64.decodeBase64(sign));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("RSA验签出错！");
        }
    }


    /**
     * 得到公钥
     *
     * @param key 密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }


    /**
     * 得到私钥
     *
     * @param key 密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }



    /**
     * @param response 返回响应解签
     * */
    public static boolean verifyResponseSign(String response){
        //排序转换成JSONObject
        JSONObject json = JSONObject.parseObject(response, Feature.OrderedField);
        final String sign =(String)json.get("sign");
        json.remove("sign");
        if (RsaUtil.verifySign(JSON.toJSONString(json),sign, "待配置的publicKey")) {
            System.out.println("------------验签成功！-------------");
            return true;
        }
        return false;
    }

}
